package com.ruoyi.eqmonitor.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.eqmonitor.dtos.*;
import com.ruoyi.eqmonitor.service.OpenApiService;
import com.ruoyi.eqmonitor.utils.OpenApiUtil;
import com.ruoyi.eqmonitor.vo.OpenApiVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Service
public class OpenApiServiceImpl implements OpenApiService {

    @Override
    public List<OpenApiVo> reportForms(OpenApiReportFormsDto dto) {
        //获取企业信息
        List<OpenApiDto> mnData = getMnData();
        //获取数据
        List<CompletableFuture<List<OpenApiVo>>> futures = new ArrayList<>();
        mnData.forEach(data -> {
            Map<String, String> map = new HashMap<>();
            map.put("type", "1");
            map.put("mn", data.getMn());
            map.put("company_id", data.getCode());

            CompletableFuture<List<OpenApiVo>> future = CompletableFuture.supplyAsync(() -> reportForms(dto, map, data))
                    .handle((result, ex) -> {
                        if (ex != null) {
                            log.error("环保数据开放接口-报表-->查询失败", ex);
                            return Collections.emptyList(); // 返回一个空列表
                        } else {
                            return result;
                        }
                    });
            futures.add(future);
        });

        List<OpenApiVo> vos = futures.stream()
                .flatMap(future -> future.join().stream())
                .collect(Collectors.toList());
        //根据时间排序
        Integer state = dto.getState();
        if (state == 1 || state == 4 || state == 5) {
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return vos.stream()
                    .sorted(Comparator.comparing(api -> LocalDate.parse(api.getTime() + "-01", dtf)))
                    .collect(Collectors.toList());
        } else if (state == 2 || state == 3) {
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return vos.stream()
                    .sorted(Comparator.comparing(api -> LocalDate.parse(api.getTime(), dtf)))
                    .collect(Collectors.toList());
        } else {
            return vos.stream().sorted(Comparator.comparingInt(api -> Integer.parseInt(api.getTime())))
                    .collect(Collectors.toList());
        }
    }

    /**
     * 获取企业信息
     * @return 企业信息集合
     */
    private static List<OpenApiDto> getMnData() {
        //查询
        String data = OpenApiUtil.doPost(new HashMap<>(), "getMnData");
        //处理数据
        List<OpenApiDto> dtos = new ArrayList<>();
        JSONObject json = JSON.parseObject(data);
        Object errmsg = json.get("errmsg");
        if ("成功".equals(errmsg)) {
            Object data0 = json.get("data");
            List<String> featuresList = JSONArray.parseArray(data0.toString(), String.class);
            featuresList.forEach(s -> {
                OpenApiDto dto = new OpenApiDto();
                JSONObject sjsonObject = JSON.parseObject(s);
                dto.setMn(sjsonObject.get("zz_mn").toString());
                String name = sjsonObject.get("zz_name").toString();
                dto.setName(name);
                String alias = name.contains("北控水务") ? "滨海污水厂" : "城区污水厂";
                dto.setAlias(alias);
                dto.setCode(sjsonObject.get("zz_code").toString());
                dtos.add(dto);
            });
        }
        return dtos;
    }

    /**
     * 查询数据并做初步处理
     */
    private static List<OpenApiVo> reportForms(OpenApiReportFormsDto dto, Map<String, String> map, OpenApiDto mnDataDto) {
        //判断进出水
        String code = mnDataDto.getName().contains("进水口") ? "进水" : "排水";
        //处理时间参数
        String beginTime0 = dto.getBeginTime();
        String endTime0 = dto.getEndTime();
        int beginYear = dto.getBeginYear();
        int endYear = dto.getEndYear();
        int beginDate = dto.getBeginDate();
        int endDate = dto.getEndDate();
        Integer state = dto.getState();
        Date beginTime = DateUtils.toDate(state, beginTime0, beginYear, beginDate,false);
        Date endTime = DateUtils.toDate(state, endTime0, endYear, endDate,true);
        //分割时间区间，区间大小小于等于167天 TODO：污水厂提供的api单次查询最多167天
        List<List<Date>> lists = new ArrayList<>();
        List<List<Date>> interval = getInterval(lists, beginTime, endTime, 167);

        List<OpenApiVo> list = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        interval.forEach(a -> {
            map.put("start_time", sdf.format(a.get(0)));
            map.put("end_time", sdf.format(a.get(1)));
            //查询数据
            String data = OpenApiUtil.doPost(map, "getDayOpenData");
            //处理json字符串
            JSONObject json = JSON.parseObject(data);
            Object errmsg = json.get("errmsg");
            if ("成功".equals(errmsg)) {
                Object data0 = json.get("data");
                List<String> featuresList = JSONArray.parseArray(data0.toString(), String.class);
                List<OpenApiVo> openApiVos = new ArrayList<>();
                featuresList.forEach(s -> {
                    OpenApiVo vo = new OpenApiVo();
                    vo.setName(mnDataDto.getName());
                    vo.setAlias(mnDataDto.getAlias());
                    vo.setCode(code);
                    JSONObject sjsonObject = JSON.parseObject(s);
                    Object time = sjsonObject.get("time");
                    vo.setTime(time.toString());
                    String data1 = sjsonObject.get("data").toString();
                    List<String> featuresList2 = JSONArray.parseArray(data1, String.class);
                    featuresList2.forEach(f -> {
                        JSONObject fObj = JSON.parseObject(f);
                        String key = fObj.get("key").toString();
                        String value = fObj.get("value").toString();
                        switch (key) {
                            case "氨氮":
                                vo.setAd(value);
                                break;
                            case "化学需氧量":
                                vo.setHxxyl(value);
                                break;
                            case "总磷":
                                vo.setZl(value);
                                break;
                            case "总氮":
                                vo.setZd(value);
                                break;
                            case "废水流量":
                                vo.setFsll(value);
                                String value2 = fObj.get("value2").toString();
                                vo.setFsll2(value2);
                                break;
                        }
                    });
                    openApiVos.add(vo);
                });
                list.addAll(openApiVos);
            }
        });

        return group(list, state);
    }

    /**
     * 按state对数据进行合并求均值处理
     * @param list 待处理的数据
     * @param state 时间标识
     * @return 结果
     */
    private static List<OpenApiVo> group(List<OpenApiVo> list, Integer state) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        if (state == null) {
            return null;
        } else if (state == 0) {
            sdf = new SimpleDateFormat("yyyy");
        } else if (state == 2 || state == 3) {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }

        SimpleDateFormat finalStf = sdf;
        List<OpenApiVo> voList = list.stream()
                .collect(Collectors.collectingAndThen(
                        //格式化时间，分组处理
                        Collectors.groupingBy(a ->
                        {
                            try {
                                return finalStf.format(finalStf.parse(a.getTime()));
                            } catch (ParseException e) {
                                log.error("环保数据开放接口-报表-格式化时间异常->{}", a.getTime());
                                e.printStackTrace();
                            }
                            return null;
                        }),
                        map -> {
                            //合并每组的成员，各数值求均值
                            List<OpenApiVo> list1 = new ArrayList<>();
                            for (Map.Entry<String, List<OpenApiVo>> entry : map.entrySet()) {
                                List<OpenApiVo> vos = entry.getValue();
                                OpenApiVo apiVo = new OpenApiVo();
                                apiVo.setName(vos.get(0).getName());
                                apiVo.setAlias(vos.get(0).getAlias());
                                apiVo.setCode(vos.get(0).getCode());
                                apiVo.setTime(entry.getKey());
                                list1.add(group2(apiVo, vos));
                            }
                            return list1;
                        })
                );
        //特殊周期进行二次处理
        int num;
        switch (state) {
            case 3:     //周
                num = 7;
                break;
            case 4:     //季
                num = 3;
                break;
            case 5:     //半年
                num = 6;
                break;
            default:
                return voList;
        }
        int finalNum = num;
        List<List<OpenApiVo>> groups = IntStream.range(0, voList.size())
                .boxed()
                //7天一组 | 3个月一组 | 6个月一组
                .collect(Collectors.groupingBy(index -> index / finalNum))
                .values()
                .stream()
                .map(indices -> indices.stream()
                        .map(voList::get)
                        .collect(Collectors.toList()))
                .collect(Collectors.toList());
        return forMerge(groups);
    }

    //整合对象
    private static List<OpenApiVo> forMerge(List<List<OpenApiVo>> lists) {
        List<OpenApiVo> list = new ArrayList<>();
        for (List<OpenApiVo> vos : lists) {
            OpenApiVo apiVo = new OpenApiVo();
            apiVo.setName(vos.get(0).getName());
            apiVo.setAlias(vos.get(0).getAlias());
            apiVo.setCode(vos.get(0).getCode());
            apiVo.setTime(vos.get(0).getTime());
            list.add(group2(apiVo, vos));
        }
        return list;
    }

    /**
     * 合并OpenApiVo,各字段求均值
     * @param apiVo 总对象
     * @param vos 对象集合
     * @return 总对象
     */
    private static OpenApiVo group2(OpenApiVo apiVo, List<OpenApiVo> vos) {
        Double adAve = vos.stream().filter(Objects::nonNull)//过滤掉为null的OpenApiVo对象
                .map(OpenApiVo::getAd).filter(StringUtils::isNotBlank) // 过滤掉值为空的元素
                .mapToDouble(Double::parseDouble).average()//转化为Double再求均值
                .orElse(0.0);// 如果为null，则返回 0.0
        Double hhxylAve = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getHxxyl).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).average().orElse(0.0);
        Double zlAve = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getZl).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).average().orElse(0.0);
        Double zdAve = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getZd).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).average().orElse(0.0);
        Double fsllAve = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getFsll).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).average().orElse(0.0);
        Double fsll2Ave = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getFsll2).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).average().orElse(0.0);
        DecimalFormat decimalFormat = new DecimalFormat("#.###");
        apiVo.setAd(decimalFormat.format(adAve));
        apiVo.setHxxyl(decimalFormat.format(hhxylAve));
        apiVo.setZl(decimalFormat.format(zlAve));
        apiVo.setZd(decimalFormat.format(zdAve));
        apiVo.setFsll(decimalFormat.format(fsllAve));
        apiVo.setFsll2(decimalFormat.format(fsll2Ave));

        double sum = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getFsll).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).sum();
        apiVo.setFsllSum(decimalFormat.format(sum));
        double sum2 = vos.stream().filter(Objects::nonNull).map(OpenApiVo::getFsll2).filter(StringUtils::isNotBlank).mapToDouble(Double::parseDouble).sum();
        apiVo.setFsll2Sum(decimalFormat.format(sum2));
        return apiVo;
    }

    /**
     * 判断区间D是否大于指定的天数num
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @param num 区间长度（天）
     * @return 区间D是否大于指定的天数num
     */
    private static boolean greaterThanC(Date beginTime, Date endTime, int num) {
        long D = beginTime.getTime() - endTime.getTime();
        long CMillis = (long) num * 24 * 60 * 60 * 1000;
        return D > CMillis;
    }

    //

    /**
     * 循环计算区间并返回
     * @param lists 时间区间集合（递归切割成多个小于等于num天的时间区间）
     * @param beginTime 区间开始时间
     * @param endTime 区间结束时间
     * @param num 区间长度（天）
     * @return 切割完成的时间区间集合
     */
    private static List<List<Date>> getInterval(List<List<Date>> lists, Date beginTime, Date endTime, int num) {
        if (endTime.getTime() - beginTime.getTime() <= 24 * 60 * 60 * 1000L) {
            List<Date> list = new ArrayList<>();
            list.add(0, beginTime);
            list.add(1, endTime);
            lists.add(list);
            return lists;
        }

        if (greaterThanC(beginTime, endTime, num)) {
            Date D = new Date((beginTime.getTime() + endTime.getTime()) / 2);
            getInterval(lists, beginTime, D, num);
            getInterval(lists, D, endTime, num);
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(beginTime);
            while (cal.getTimeInMillis() < endTime.getTime()) {
                Date d2 = new Date(cal.getTimeInMillis() + num * 24 * 60 * 60 * 1000L);
                if (d2.getTime() > endTime.getTime()) {
                    d2 = endTime;
                }
                List<Date> list = new ArrayList<>();
                list.add(0, cal.getTime());
                list.add(1, d2);
                lists.add(list);
                cal.add(Calendar.DATE, num);
            }
        }
        return lists;
    }

    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date A = sdf.parse("2022-01-01");
        Date B = sdf.parse("2023-01-01");
        int C = 100;
        List<List<Date>> lists = new ArrayList<>();
        List<List<Date>> interval = getInterval(lists, A, B, C);
        interval.forEach(a -> {
            long l = (a.get(0).getTime() - a.get(1).getTime()) / (24 * 60 * 60 * 1000L);
            System.out.println(sdf.format(a.get(0)) + "------" + sdf.format(a.get(1)) + "------" + l);
        });
    }

}
